package com.lan.model.symbol;


import com.lan.model.Symbol;
import com.lan.model.Type;
import com.lan.model.type.FunctionType;

import java.util.LinkedList;
import java.util.List;

public abstract class Scope extends Symbol {

    // 该Scope中的成员，包括变量、方法、类等。
    protected List<Symbol> symbols = new LinkedList<>();

    /**
     * 向scope中添加符号，同时设置好该符号的enclosingScope
     *
     * @param symbol
     */
    public void addSymbol(Symbol symbol) {
        symbols.add(symbol);
        symbol.setScope(this);
    }

    /**
     * 是否包含某个Variable
     *
     * @param name
     * @return
     */
    public Variable getVariable(String name) {
        return getVariable(this, name);
    }

    public static Variable getVariable(Scope scope, String name) {
        for (Symbol s : scope.symbols) {
            if (s instanceof Variable && name.equalsIgnoreCase(s.getName())) {
                return (Variable) s;
            }
        }
        return null;
    }

    /**
     * 是否包含某个Function
     *
     * @param name
     * @param paramTypes 参数类型。不允许为空。该参数不允许为空。如果没有参数，需要传入一个0长度的列表。
     * @return
     */
    public Function getFunction(String name, List<Type> paramTypes) {
        return getFunction(this, name, paramTypes);
    }

    /**
     * 是否包含某个Function。这是个静态方法，可以做为工具方法重用。避免类里要超找父类的情况。
     *
     * @param scope
     * @param name
     * @param paramTypes
     * @return
     */
    public static Function getFunction(Scope scope, String name, List<Type> paramTypes) {
        Function rtn = null;
        for (Symbol s : scope.symbols) {
            if (s instanceof Function && name.equalsIgnoreCase(s.getName())) {
                Function function = (Function) s;
                if (function.matchParameterTypes(paramTypes)) {
                    rtn = function;
                    break;
                }
            }
        }
        return rtn;
    }

    /**
     * 获取一个函数类型的变量，能匹配相应的参数类型
     *
     * @param name
     * @param paramTypes
     * @return
     */
    public Variable getFunctionVariable(String name, List<Type> paramTypes) {
        return getFunctionVariable(this, name, paramTypes);
    }

    public static Variable getFunctionVariable(Scope scope, String name, List<Type> paramTypes) {
        Variable rtn = null;
        for (Symbol s : scope.symbols) {
            if (s instanceof Variable && ((Variable) s).type instanceof FunctionType && name.equalsIgnoreCase(s.getName())) {
                Variable v = (Variable) s;
                FunctionType functionType = (FunctionType) v.type;
                if (functionType.matchParameterTypes(paramTypes)) {
                    rtn = v;
                    break;
                }
            }
        }

        return rtn;
    }

    /**
     * 是否包含某个Class
     *
     * @param name
     * @return
     */
    public Clazz getClass(String name) {
        return getClass(this, name);
    }

    public static Clazz getClass(Scope scope, String name) {
        for (Symbol s : scope.symbols) {
            if (s instanceof Clazz && name.equalsIgnoreCase(s.getName())) {
                return (Clazz) s;
            }
        }
        return null;
    }


    /**
     * 是否包含某个Symbol
     *
     * @param symbol
     * @return
     */
    public boolean containsSymbol(Symbol symbol) {
        return symbols.contains(symbol);
    }


    public List<Symbol> getSymbols() {
        return symbols;
    }


    @Override
    public String toString() {
        return "Scope: " + name;
    }

}